package com.guang.springbootselfmvc.looger;

import com.guang.springbootselfmvc.exception.ServiceException;
import com.guang.springbootselfmvc.exception.ServiceExceptions;
import com.guang.springbootselfmvc.utils.JsonUtil;
import com.guang.springbootselfmvc.utils.StringUtil;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

@Aspect
public class ExceptionAspect {
    private static Logger logger = LoggerFactory.getLogger(ExceptionAspect.class);
    public static final ConcurrentHashMap<String, String> map = new ConcurrentHashMap();

    public ExceptionAspect() {
    }

    @Pointcut("execution(public * com.guang..controller..*(..))")
    public void controllerPointCut() {
    }

    @Before("controllerPointCut()")
    public void before(JoinPoint joinPoint) {
        String url = "";
        String urlMappingName = "";

        try {
            ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
            if (requestAttributes == null) {
                logger.error("获取不到Request信息");
                return;
            }

            url = requestAttributes.getRequest().getRequestURI();
            String methodName = joinPoint.getSignature().getName();
            if (ExceptionAspect.map.get(url) == null) {
                urlMappingName = this.getMethodMapping(joinPoint, url, methodName);
                ExceptionAspect.map.put(url, urlMappingName);
            } else {
                urlMappingName = (String)ExceptionAspect.map.get(url);
            }

            Object[] args = joinPoint.getArgs();
            List<Object> params = new ArrayList();
            Object[] var8 = args;
            int var9 = args.length;

            for(int var10 = 0; var10 < var9; ++var10) {
                Object obj = var8[var10];
                if (obj != null) {
                    if (obj instanceof MultipartFile) {
                        MultipartFile file = (MultipartFile)obj;
                        String name = file.getOriginalFilename();
                        long size = file.getSize();
                        String fileSize;
                        if (size > 1048576L) {
                            fileSize = size / 1048576L + "M";
                        } else if (size > 1024L) {
                            fileSize = size / 1024L + "K";
                        } else {
                            fileSize = size + "B";
                        }

                        Map<String, String> map = new HashMap();
                        map.put(name, fileSize);
                        params.add(map);
                    } else if (!(obj instanceof ServletRequest) && !(obj instanceof ServletResponse)) {
                        params.add(obj);
                    }
                }
            }

            if (params.size() > 0) {
                String param;
                if (args.length == 1) {
                    param = JsonUtil.parseObjectToJsonString(params.get(0));
                } else {
                    param = JsonUtil.parseObjectToJsonString(params);
                }

                logger.info("开始访问{}接口:{},携带参数: {}", new Object[]{urlMappingName, url, param});
            } else {
                logger.info("开始访问{}接口:{}", urlMappingName, url);
            }
        } catch (Exception var18) {
            logger.error("访问" + urlMappingName + "接口" + url + "打印参数日志异常", var18);
        }

    }

    @AfterThrowing(
        value = "controllerPointCut()",
        throwing = "e"
    )
    public void afterThrow(JoinPoint joinPoint, ServiceException e) {
        String url = "";
        String urlMappingName = "";

        try {
            ServletRequestAttributes requestAttributes = (ServletRequestAttributes)RequestContextHolder.getRequestAttributes();
            if (requestAttributes == null) {
                logger.error("获取不到Request信息");
                return;
            }

            url = requestAttributes.getRequest().getRequestURI();
            String controllerMethodName = joinPoint.getSignature().getName();
            if (map.get(url) == null) {
                urlMappingName = this.getMethodMapping(joinPoint, url, controllerMethodName);
                map.put(url, urlMappingName);
            } else {
                urlMappingName = (String)map.get(url);
            }

            StackTraceElement[] stackTrace = e.getStackTrace();
            if (stackTrace != null && stackTrace.length > 0) {
                StackTraceElement[] var16 = stackTrace;
                int var10 = stackTrace.length;

                for(int var11 = 0; var11 < var10; ++var11) {
                    StackTraceElement s = var16[var11];
                    if (!s.getClassName().equals(ServiceExceptions.class.getName())) {
                        String className = s.getClassName();
                        String methodName = s.getMethodName();
                        if (e.getCause() != null) {
                            logger.error("访问" + urlMappingName + "接口" + url + "抛出异常信息:" + className + "." + methodName, e);
                        } else {
                            logger.error("访问" + urlMappingName + "接口" + url + "抛出异常信息:" + className + "." + methodName + ":" + e.getErrMsg(), e);
                        }
                        break;
                    }
                }
            } else {
                String className = joinPoint.getTarget().getClass().getName();
                String methodName = joinPoint.getSignature().getName();
                if (e.getCause() != null) {
                    logger.error(className + "." + methodName, e);
                } else {
                    logger.error(className + "." + methodName + ":" + e.getErrMsg());
                }
            }
        } catch (Exception var15) {
            logger.error("访问" + urlMappingName + "接口" + url + "抛出异常信息打印失败", var15);
        }

    }

    @AfterReturning(
        value = "controllerPointCut()",
        returning = "obj"
    )
    public void afterReturn(JoinPoint joinPoint, Object obj) {
        String url = "";
        String urlMappingName = "";

        try {
            ServletRequestAttributes requestAttributes = (ServletRequestAttributes)RequestContextHolder.getRequestAttributes();
            if (requestAttributes == null) {
                logger.error("获取不到Request信息");
                return;
            }

            url = requestAttributes.getRequest().getRequestURI();
            String methodName = joinPoint.getSignature().getName();
            if (map.get(url) == null) {
                urlMappingName = this.getMethodMapping(joinPoint, url, methodName);
                map.put(url, urlMappingName);
            } else {
                urlMappingName = (String)map.get(url);
            }

            url = requestAttributes.getRequest().getRequestURI();
            logger.info("正常访问{}接口{}结束, 返回结果:{}", new Object[]{urlMappingName, url, obj.toString()});
        } catch (Exception var7) {
            logger.error("访问" + urlMappingName + "接口" + url + "返回日志打印异常");
        }

    }

    public String getMethodMapping(JoinPoint joinPoint, String url, String methodName) throws NoSuchMethodException {
        String urlMappingName = "";
        boolean status = false;
        MethodSignature signature = (MethodSignature)joinPoint.getSignature();
        Method method = signature.getMethod();
        RequestMapping requestMapping;
        String[] value;
        if ((requestMapping = (RequestMapping)method.getDeclaredAnnotation(RequestMapping.class)) != null) {
            value = requestMapping.value();
            if (value.length > 0 && url.contains(value[0])) {
                urlMappingName = requestMapping.name();
                status = true;
            }
        } else {
            PostMapping postMapping;
            if ((postMapping = (PostMapping)method.getDeclaredAnnotation(PostMapping.class)) != null) {
                value = postMapping.value();
                if (value.length > 0 && url.contains(value[0])) {
                    urlMappingName = postMapping.name();
                    status = true;
                }
            } else {
                GetMapping getMapping;
                if ((getMapping = (GetMapping)method.getDeclaredAnnotation(GetMapping.class)) != null) {
                    value = getMapping.value();
                    if (value.length > 0 && url.contains(value[0])) {
                        urlMappingName = getMapping.name();
                        status = true;
                    }
                } else {
                    DeleteMapping deleteMapping;
                    if ((deleteMapping = (DeleteMapping)method.getDeclaredAnnotation(DeleteMapping.class)) != null) {
                        value = deleteMapping.value();
                        if (value.length > 0 && url.contains(value[0])) {
                            urlMappingName = deleteMapping.name();
                            status = true;
                        }
                    } else {
                        PutMapping putMapping;
                        if ((putMapping = (PutMapping)method.getDeclaredAnnotation(PutMapping.class)) != null) {
                            value = putMapping.value();
                            if (value.length > 0 && url.contains(value[0])) {
                                urlMappingName = putMapping.name();
                                status = true;
                            }
                        } else {
                            PatchMapping patchMapping;
                            if ((patchMapping = (PatchMapping)method.getDeclaredAnnotation(PatchMapping.class)) != null) {
                                value = patchMapping.value();
                                if (value.length > 0 && url.contains(value[0])) {
                                    urlMappingName = patchMapping.name();
                                    status = true;
                                }
                            }
                        }
                    }
                }
            }
        }

        if (!status) {
            logger.error("接口{}的路径映射Mapping类型注解超出定义范围", url);
        } else if (StringUtil.isEmpty(urlMappingName)) {
            logger.info("接口{}的路径映射Mapping类型注解无定义name属性", url);
            urlMappingName = "";
        }

        return urlMappingName;
    }
}